<script>
import { GlLink, GlIcon, GlSkeletonLoader } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { s__, __ } from '~/locale';
import securityTrainingProvidersQuery from '~/security_configuration/graphql/security_training_providers.query.graphql';
import securityTrainingVulnerabilityQuery from '~/security_configuration/graphql/security_training_vulnerability.query.graphql';
import Tracking from '~/tracking';
import {
  TRACK_CLICK_TRAINING_LINK_ACTION,
  TRACK_TRAINING_LOADED_ACTION,
} from '~/security_configuration/constants';
import { TEMP_PROVIDER_LOGOS } from '~/security_configuration/components/constants';
import { SECURITY_TRAINING_URL_STATUS_COMPLETED } from '../constants';
import { formatIdentifierExternalIds, isSupportedIdentifier } from '../helpers';

export const i18n = {
  trainingUnavailable: s__('Vulnerability|Training not available for this vulnerability.'),
  viewTraining: s__('Vulnerability|View training'),
  loading: __('Loading'),
};

export const TRAINING_URL_POLLING_INTERVAL = 5000;

export default {
  i18n,
  TEMP_PROVIDER_LOGOS,
  SECURITY_TRAINING_URL_STATUS_COMPLETED,
  components: {
    GlLink,
    GlIcon,
    GlSkeletonLoader,
  },
  directives: {
    SafeHtml,
  },
  mixins: [Tracking.mixin()],
  props: {
    projectFullPath: {
      type: String,
      required: true,
    },
    identifiers: {
      type: Array,
      required: true,
    },
    file: {
      type: String,
      required: false,
      default: null,
    },
  },
  apollo: {
    securityTrainingProviders: {
      query: securityTrainingProvidersQuery,
      update({ project }) {
        return project?.securityTrainingProviders;
      },
      error(e) {
        Sentry.captureException(e);
      },
      variables() {
        return {
          fullPath: this.projectFullPath,
        };
      },
    },
    securityTrainingUrls: {
      query: securityTrainingVulnerabilityQuery,
      pollInterval: TRAINING_URL_POLLING_INTERVAL,
      update({ project }) {
        if (!project) {
          return [];
        }
        const { securityTrainingUrls = [] } = project;

        const allUrlsAreReady = securityTrainingUrls.every(
          ({ status }) => status === SECURITY_TRAINING_URL_STATUS_COMPLETED,
        );

        if (allUrlsAreReady) {
          this.$apollo.queries.securityTrainingUrls.stopPolling();
          this.isUrlsLoading = false;
        }

        return securityTrainingUrls;
      },
      variables() {
        const { file } = this;

        return {
          projectFullPath: this.projectFullPath,
          identifierExternalIds: this.supportedIdentifiersExternalIds,
          ...(file && { filename: file }),
        };
      },
      error(e) {
        Sentry.captureException(e);
      },
    },
  },
  data() {
    return {
      securityTrainingProviders: [],
      vulnerability: {},
      training: null,
      isUrlsLoading: true,
    };
  },
  computed: {
    showVulnerabilityTraining() {
      return Boolean(this.hasSecurityTrainingProviders);
    },
    showTrainingNotFound() {
      return !this.hasSupportedIdentifier || !this.hasSecurityTrainingUrls;
    },
    hasSecurityTrainingProviders() {
      return this.securityTrainingProviders?.some(({ isEnabled }) => isEnabled);
    },
    supportedIdentifiersExternalIds() {
      return this.identifiers.flatMap((identifier) =>
        isSupportedIdentifier(identifier.externalType)
          ? formatIdentifierExternalIds(identifier)
          : [],
      );
    },
    hasSupportedIdentifier() {
      return this.supportedIdentifiersExternalIds.length > 0;
    },
    hasSecurityTrainingUrls() {
      return this.securityTrainingUrls?.length > 0;
    },
  },
  watch: {
    showVulnerabilityTraining: {
      immediate: true,
      handler(showVulnerabilityTraining) {
        this.$emit('show-vulnerability-training', showVulnerabilityTraining);
      },
    },
  },
  created() {
    const unwatchHasSecurityTrainingUrls = this.$watch('hasSecurityTrainingUrls', (hasUrls) => {
      if (hasUrls) {
        this.track(TRACK_TRAINING_LOADED_ACTION, {
          property: this.projectFullPath,
        });
        // we only want to track this once, so we immediately unsubscribe after the first track
        unwatchHasSecurityTrainingUrls();
      }
    });
  },
  methods: {
    clickTrainingLink(name, identifier) {
      this.track(TRACK_CLICK_TRAINING_LINK_ACTION, {
        label: `vendor_${name}`,
        property: this.projectFullPath,
        extra: {
          vulnerability: identifier,
        },
      });
    },
  },
};
</script>

<template>
  <div v-if="showVulnerabilityTraining">
    <slot name="header"></slot>
    <p v-if="showTrainingNotFound" data-testid="unavailable-message">
      {{ $options.i18n.trainingUnavailable }}
    </p>
    <div v-else-if="isUrlsLoading">
      <gl-skeleton-loader :width="200" :lines="3" />
    </div>
    <div
      v-for="({ name, url, identifier, status }, index) in securityTrainingUrls"
      :key="index"
      class="gl-mt-6"
    >
      <div v-if="status === $options.SECURITY_TRAINING_URL_STATUS_COMPLETED">
        <div>
          <span v-if="$options.TEMP_PROVIDER_LOGOS[name]" class="gl-mr-1 gl-display-inline-flex">
            <div
              v-safe-html="$options.TEMP_PROVIDER_LOGOS[name].svg"
              data-testid="provider-logo"
              style="width: 12px"
              role="presentation"
            ></div>
          </span>
          <span class="gl-font-weight-bold gl-font-base" data-testid="security-training-text">{{
            name
          }}</span>
        </div>
        <gl-link
          :href="url"
          target="_blank"
          data-testid="security-training-link"
          :data-qa-training-name="name"
          @click="clickTrainingLink(name, identifier)"
        >
          {{ $options.i18n.viewTraining }}
          <gl-icon class="gl-ml-2" name="external-link" :size="12" />
        </gl-link>
      </div>
    </div>
  </div>
</template>
